package kr.ac.ssu.ailab.Control;

import java.util.ArrayList;
import java.util.Vector;

import kr.ac.ssu.ailab.Model.Data.Cell;
import kr.ac.ssu.ailab.Model.Data.Cluster;

/**
 * 이 클래스는 P2P Hub 방식의 A-STAR 알고리즘에서 사용하는 Cluster의 주변 Adjacent CLuster들과의
 * Connection여부를 확인하여 1차 abstraction 그래프를 생성한다. 그래프를 생성하는 과정에서 여러번 반복되는 것을 방지하기
 * 위해 각 Cluster의 Connected List 와 Failed List를 검사하여 중복된 검사를 최소화 시킨다. 또한 생성된 그래프의
 * 시각적인 확인이 가능하다.
 * 
 * @author Neil
 * */
public class ClusterSearch
{
	private transient Vector<ArrayList<Cell>> candiList = null;
	private transient GraphControl graphControl = null;
	private ClusterSearch clusterSearch = null;

	/**
	 * Constructor
	 */
	public ClusterSearch()
	{
		candiList = null;
		graphControl = graphControl.getInstance();
	}

	/**
	 * 맵에 변경이 있을때 한 Cluster 와 주변의 Cluster 의 연결성을 조사한다.
	 * 
	 * @param SeqList
	 */
	public void repartialSearch(ArrayList<Integer> SeqList)
	{
		ClusterControl CCInstance = ClusterControl.getInstance();
		Cell startCell = null;
		ArrayList<Cell> finishCell = null;

		SearchModule partialSearch = null;

		int number = SeqList.get(0);
		Cluster startCluster = CCInstance.getCluster(number);
		Cluster finishCluster = null;
		candiList = CCInstance.getCandiCells();

		for (int i = 0; i < candiList.get(number).size(); i++)
		{
			startCell = candiList.get(number).get(i);

			for (int j = 1; j < SeqList.size(); j++)
			{
				int temp = SeqList.get(j);
				finishCluster = CCInstance.getCluster(temp);
				finishCell = finishCluster.getStandCell();

				for (int k = 0; k < finishCell.size(); k++)
				{
					partialSearch = new SearchModule(startCell, finishCell.get(k));
					partialSearch.startSearch();
					if (partialSearch.isResult())
					{

						startCluster.addConnectedList(finishCluster.getSeqCluster());
						finishCluster.addConnectedList(startCluster.getSeqCluster());

						startCluster.addStandCell(startCell);

						CellControl.setStandCell(startCell);

						finishCluster.addStandCell(finishCell.get(k));
						CellControl.setStandCell(finishCell.get(k));

						GraphControl.getInstance().addEdge(startCell, finishCell.get(k));
						GraphControl.getInstance().addEdgeCost(startCell, finishCell.get(k),
								partialSearch.getResult_score());
						break;
					}
					else
					{

						startCluster.addfailedList(finishCluster.getSeqCluster());
						finishCluster.addfailedList(startCluster.getSeqCluster());
					}

				}

			}
			if (partialSearch.isResult())
			{
				break;
			}

		}

		clearCandiCSC();
	}

	/**
	 * 한 Cluster 와 주변의 Cluster 의 연결성을 검사한다
	 */
	public void partialSearch()
	{
		ClusterControl CCInstance = ClusterControl.getInstance();
		Cell startCell = null;
		Cell finishCell = null;

		candiList = CCInstance.getCandiCells();

		SearchModule partialSearch = null;
		for (int i = 0; i < candiList.size(); i++)
		{

			Cluster startCluster = CCInstance.getCluster(i);

			Cluster next[] = CCInstance.getAdjacentCluster(startCluster);

			for (int k = 0; k < next.length; k++)
			{
				for (int j = 0; j < candiList.get(i).size(); j++)
				{

					startCell = candiList.get(i).get(j);

					for (int l = 0; l < candiList.get(next[k].getSeqCluster()).size(); l++)
					{

						if (startCluster.getConnectedList().contains((next[k].getSeqCluster()))
								|| startCluster.getFailedList().contains((next[k].getSeqCluster())))
						{
							break;
						}
						finishCell = candiList.get(next[k].getSeqCluster()).get(l);
						partialSearch = new SearchModule(startCell, finishCell);
						partialSearch.startSearch();

						if (partialSearch.isResult())
						{

							startCluster.addConnectedList(next[k].getSeqCluster());
							next[k].addConnectedList(startCluster.getSeqCluster());

							startCluster.addStandCell(startCell);

							CellControl.setStandCell(startCell);

							next[k].addStandCell(finishCell);
							CellControl.setStandCell(finishCell);

							GraphControl.getInstance().addEdge(startCell, finishCell);
							GraphControl.getInstance().addEdgeCost(startCell, finishCell,
									partialSearch.getResult_score());
							break;
						}
						else
						{

							startCluster.addfailedList(next[k].getSeqCluster());
							next[k].addfailedList(startCluster.getSeqCluster());
						}

					}

					if (partialSearch.isResult())
					{
						break;
					}
				}

			}
		}
		clearCandiCSC();
	}

	/**
	 * CSC로 판명된 Candidate Cell을 제외하고 나머지는 Normal 로 지정.
	 * */
	public void clearCandiCSC()
	{
		for (int i = 0; i < candiList.size(); i++)
		{
			for (int j = 0; j < candiList.get(i).size(); j++)
			{

				if (candiList.get(i).get(j).getType() != CellControl.STAND_CELL)
				{
					candiList.get(i).get(j).setType(CellControl.NORMAL);

				}
			}
		}
		candiList = null;
	}

	/**
	 * 한 Cluster 와 주변의 Cluster 의 연결성을 재검사한다
	 * 
	 * @return null
	 */
	public void REpartialSearch()
	{
		ClusterControl CCInstance = ClusterControl.getInstance();
		Cell startCell = null;
		Cell finishCell = null;

		candiList = CCInstance.getCandiCells();

		SearchModule partialSearch = null;
		for (int i = 0; i < candiList.size(); i++)
		{

			Cluster startCluster = CCInstance.getCluster(i);

			Cluster next[] = CCInstance.getAdjacentCluster(startCluster);

			for (int k = 0; k < next.length; k++)
			{
				for (int j = 0; j < candiList.get(i).size(); j++)
				{

					startCell = candiList.get(i).get(j);

					for (int l = 0; l < candiList.get(next[k].getSeqCluster()).size(); l++)
					{

						finishCell = candiList.get(next[k].getSeqCluster()).get(l);
						partialSearch = new SearchModule(startCell, finishCell);
						partialSearch.startSearch();

						if (partialSearch.isResult())
						{

							startCluster.addConnectedList(next[k].getSeqCluster());
							next[k].addConnectedList(startCluster.getSeqCluster());

							startCluster.addStandCell(startCell);

							CellControl.setStandCell(startCell);

							next[k].addStandCell(finishCell);
							CellControl.setStandCell(finishCell);

							GraphControl.getInstance().addEdge(startCell, finishCell);
							GraphControl.getInstance().addEdgeCost(startCell, finishCell,
									partialSearch.getResult_score());
							break;
						}
						else
						{

							startCluster.addfailedList(next[k].getSeqCluster());
							next[k].addfailedList(startCluster.getSeqCluster());
						}

					}
					if (partialSearch.isResult())
					{
						break;
					}
				}

			}
		}
		clearCandiCSC();
	}

}
